﻿using System;
using System.Windows;
using nRoute.Components;
using nRoute.Internal;
using nRoute.Navigation;
using nRoute.Components.Routing;
using nRoute.Navigation.Containers;

namespace nRoute.Controls
{
    public partial class NavigationContentControl
         : INavigationHandler, ISupportRefreshNavigation
    {
        private const string NAVIGATIONURL_NOTNULLOREMPTY = "Request's navigation url cannot be null or empty.";
        
#region INavigationHandler Members

        void INavigationHandler.ProcessRequest(NavigationRequest request, Action<bool> requestCallback)
        {
            OnProcessRequest(request, requestCallback);
        }

        void INavigationHandler.ProcessResponse(NavigationResponse response)
        {
            OnProcessResponse(response);
        }

#endregion

#region Overriden Methods

        protected virtual void OnUrlChanged(string oldUrl, string newUrl)
        {
            if (string.IsNullOrEmpty(newUrl)) return;
            var _currentUrl = CurrentNavigationRequest != null ? CurrentNavigationRequest.RequestUrl : null;

            // if our requested url is not equal to our current url then navigate
            if (!string.Equals(_currentUrl, newUrl, StringComparison.OrdinalIgnoreCase))
            {
                Navigate(newUrl);
            }
        }

        protected virtual void OnNavigate(NavigationRequest request)
        {
            Guard.ArgumentNotNull(request, "request");
            Guard.ArgumentValue(string.IsNullOrEmpty(request.RequestUrl), "request", NAVIGATIONURL_NOTNULLOREMPTY);

            NavigationService.Navigate(request, this);
        }

        protected virtual void OnProcessRequest(NavigationRequest request, Action<bool> requestCallback)
        {
            Guard.ArgumentNotNull(request, "request");
            Guard.ArgumentNotNull(requestCallback, "requestCallback");

            // if there is a pending request
            if (ActiveNavigationRequest != null)
            {
                NavigationService.CancelNavigation(ActiveNavigationRequest);
                ActiveNavigationRequest = null;
            }
            
            // we check if our current page supports ISupportNavigation, if so we defer to it
            if (CurrentNavigationLifecycleSupporter != null)
            {
                CurrentNavigationLifecycleSupporter.Closing((b) =>
                {
                    if (b)
                    {
                        ActiveNavigationRequest = request;
                        TransitionToNavigationState(Controls.NavigationState.Navigating);
                    }
                    requestCallback(b);
                });
            }
            else
            {
                ActiveNavigationRequest = request;
                TransitionToNavigationState(Controls.NavigationState.Navigating);
                requestCallback(true);
            }
        }

        protected virtual void OnProcessResponse(NavigationResponse response)
        {
            Guard.ArgumentNotNull(response, "response");

            // we won't handle it the response, if it is not the active request!
            if (!response.Request.Equals(ActiveNavigationRequest)) return;
            
            // we check if the navigation was successfull or not
            if (response.Status != ResponseStatus.Success)
            {
                // if cancelled then return to normal state, else we inform the error 
                if (response.Status == ResponseStatus.Cancelled)
                {
                    TransitionToNavigationState(Controls.NavigationState.Navigated);
                    return;
                }
                ShowFailedNavigationState(response.Request, response.Status, response.Error);
                return;
            }

            // we save our supporters and use them - note_ we need to save this to access later
            CurrentNavigationLifecycleSupporter = response.NavigationLifecycleSupporter;
            CurrentNavigationStateSupporter = response.NavigationStateSupporter;

            // if the content support navigation, we pass in the request/response merged parameters
            if (this.CurrentNavigationLifecycleSupporter != null)
            {
                CurrentNavigationLifecycleSupporter.Initialize(response.ResponseParameters);
                Title = CurrentNavigationLifecycleSupporter.Title ?? 
                    nRoute.Navigation.Navigation.GetTitle(response.Content as DependencyObject);
            }
            else
            {
                Title = nRoute.Navigation.Navigation.GetTitle(response.Content as DependencyObject);
            }
            
            // we save the url and the content
            CurrentNavigationRequest = response.Request;
            SetValue(ContentProperty, response.Content);
            TransitionToNavigationState(Controls.NavigationState.Navigated);
        }

#endregion

#region ISupportRefreshNavigation Members

        public bool CanRefresh
        {
            get { return (CurrentNavigationRequest != null); }
        }

        public void Refresh()
        {
            if (CurrentNavigationRequest != null)
            {
                var _refreshRequest = new NavigationRequest(CurrentNavigationRequest.RequestUrl, 
                    CurrentNavigationRequest.RequestParameters, CurrentNavigationRequest.SiteArea, NavigateMode.Refresh);
                NavigationService.Navigate(_refreshRequest, this);
            }
        }

#endregion

    }
}
